package com.ziytek.web.citizen.service;

import com.google.gson.Gson;
import com.ziytek.web.citizen.caffeine.CachePutOrGet;
import com.ziytek.web.citizen.config.caffeine.CaffeineUtil;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.enums.StepTypeNoEnum;
import com.ziytek.web.citizen.model.bean.CommandFirst;
import com.ziytek.web.citizen.model.bean.CommandIssuedSuccess;
import com.ziytek.web.citizen.model.bean.FirstDataNotNormalCache;
import com.ziytek.web.citizen.model.data.RealData;
import com.ziytek.web.citizen.util.CabinetNoUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 定时任务处理
 *
 * @author fenghx
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class JobService {
    private final Gson gson;
    private final DoorsService doorsService;
    private final CachePutOrGet cachePutOrGet;
    private final JobReStartService jobReStartService;

    public void jobStart(Object msg) {
        Assert.notNull(msg, "realData is null");
        if (!(msg instanceof RealData rd)) {
            return;
        }

        var cab = rd.getB();
        var keyAll = CaffeineUtil.FIRST_DATA_ALL_CACHE_PREFIX + cab;
        var keySingle = CaffeineUtil.FIRST_DATA_SINGLE_CACHE_PREFIX + cab;
        List<CommandIssuedSuccess> allList = cachePutOrGet.getCommandIssuedSuccessStartWith(keyAll);
        List<CommandIssuedSuccess> singleList = cachePutOrGet.getCommandIssuedSuccessStartWith(keySingle);
        // 不需要判断第一帧数据
        if (CollectionUtils.isEmpty(allList) && CollectionUtils.isEmpty(singleList)) {
            //log.info("判断第一帧数据查询缓存为空:{}-{}", keyAll, keySingle);
            return;
        }

        Assert.notNull(rd.getB(), "realData.b is null");
        rd.setBd(null);

        if (!CollectionUtils.isEmpty(singleList)) {
            singleList.forEach(s -> singleJudgeFirstData(rd, s));
        }

        if (!CollectionUtils.isEmpty(allList)) {
            allList.forEach(a -> judgeFirstData(rd, a));
        }
    }

    private void judgeFirstData(RealData rd, CommandIssuedSuccess command) {
        Pair<Boolean, List<Integer>> pair = allCheck(command, rd.getB());
        if (null == pair || CollectionUtils.isEmpty(pair.getRight())) {
            return;
        }

        var cab = rd.getB();
        List<Integer> boardNoList = pair.getRight();

        boolean isSl = StepTypeNoEnum.STEP_TYPE_SL_NUM.getCode().equalsIgnoreCase(command.getSetType());
        var thread = Thread.startVirtualThread(() -> rd.getD().forEach(b -> b.getD().forEach(o -> {
            // 不需要处理的分控板电池通道
            if (null == b.getC() || !boardNoList.contains(b.getC())) {
                //log.info("不处理分控板电池通道:{},boardNo:{}", b.getC(), boardNoList.contains(b.getC()));
                return;
            }

            var current = Math.abs(o.getC());
            var voltage = Math.abs(o.getV());
            var currentNormal = current > NumConstant.INT_FIFTY;
            var voltageNormal = voltage > NumConstant.INT_TWO_THOUSAND;

            // 1、不是搁置工步 电流大于50mA而且电压大于2V,可视为第一帧数据 2、搁置工步 电压大于2V,可视为第一帧数据
            boolean isSlTypeFirstData = isSl && voltageNormal;
            boolean isNotSlTypeFirstData = !isSl && currentNormal && voltageNormal;
            // 不是搁置工艺的电压大于2V而且电流小于50mA的属于小电流,视为无效数据
            boolean isNotSlTypeButCurrentNotNormal = !isSl && voltageNormal && !currentNormal;

            setCache(currentNormal, voltageNormal, isNotSlTypeButCurrentNotNormal, cab, b.getC(), o.getP());
            if (isNotSlTypeButCurrentNotNormal) {
                return;
            }

            if (isSlTypeFirstData || isNotSlTypeFirstData) {
                var notNormalKey = CaffeineUtil.FIRST_DATA_NOT_NORMAL_CACHE_KEY + CaffeineUtil.getCacheKey(cab, b.getC(), o.getP());
                CaffeineUtil.delete(notNormalKey);
                var key = CaffeineUtil.FIRST_DATA_CACHE_PREFIX + CaffeineUtil.getCacheKey(cab, b.getC(), o.getP());
                // 查询需要判断第一帧数据的缓存
                CommandFirst cache = CaffeineUtil.get(key);
                if (null == cache) {
                    //log.info("[all]首个上送数据缓存CommandFirst查询不到key:{}", key);
                    return;
                }

                cache.setBoardNo(b.getC());
                cache.setChannelNo(o.getP());
                // 定时任务开启成功，删除缓存
                if (jobReStartService.singleChannelJob(cache)) {
                    CaffeineUtil.delete(key);
                }
            }
        })));

        try {
            thread.join();
        } catch (InterruptedException e) {
            log.error("channelRead:{}", e.getMessage());
        }

        // 查询是否是全部有正常数据
        boolean isNormal = hasNormal(cab);
        boolean isVolNormal = hasVolNormal(cab);
        if (!isSl && !isNormal) {
            log.info("整体设置定时失败 未找到任一个电流大于50mA {}", gson.toJson(command));
            return;
        }

        if (isSl && !isVolNormal) {
            log.info("整体设置定时失败 搁置指令未找到任一个电流大于50mA {}", gson.toJson(command));
            return;
        }

        var cacheKey = CaffeineUtil.getCacheKey(cab, command.getBoardNo(), command.getChannelNo(), command.getOrder());
        Long firstCommand = CaffeineUtil.get(CaffeineUtil.CACHE_KEY_COMMAND_FIRST + cacheKey);
        if (null == firstCommand) {
            log.info("整体设置定时失败 firstCommand为空 key:{}-{}", cacheKey, gson.toJson(command));
            return;
        }

        //log.info("总指令查询需要判断第一帧数据的缓存,{},{}", allCommand, cab);
        // 时间增加3秒，保证指令下发成功后，定时任务能立即执行
        var time = command.getExpectedTimeSecond() * NumConstant.LONG_ONE + NumConstant.LONG_THREE;
        CaffeineUtil.delete(CaffeineUtil.CACHE_KEY_COMMAND + cacheKey);
        CaffeineUtil.set(CaffeineUtil.CACHE_KEY_COMMAND + cacheKey, command, time);
        log.info("整体指令设置定时key:{},time:{}-{}", cacheKey, time, gson.toJson(command));

        //CaffeineUtil.delete(CaffeineUtil.FIRST_DATA_ALL_CACHE_PREFIX + cab);
        CaffeineUtil.delete(CaffeineUtil.CACHE_KEY_COMMAND_FIRST + cacheKey);
    }

    private void singleJudgeFirstData(RealData rd, CommandIssuedSuccess command) {
        Pair<Boolean, List<Integer>> pair = singleCheck(command, rd.getB());
        if (null == pair || CollectionUtils.isEmpty(pair.getRight())) {
            return;
        }

        var cab = rd.getB();
        List<Integer> boardNoList = pair.getRight();

        AtomicInteger currentNum = new AtomicInteger(NumConstant.INT_ONE);
        AtomicInteger voltageNum = new AtomicInteger(NumConstant.INT_ONE);

        var isSl = StepTypeNoEnum.STEP_TYPE_SL_NUM.getCode().equalsIgnoreCase(command.getSetType());
        var thread = Thread.startVirtualThread(() -> rd.getD().forEach(b -> b.getD().forEach(o -> {
            // 不需要处理的分控板电池通道
            if (null == b.getC() || !boardNoList.contains(b.getC())) {
                //log.info("不处理分控板电池通道:{},boardNo:{}", b.getC(), boardNoList.contains(b.getC()));
                return;
            }

            // 不是单个通道的
            if (!(b.getC().equals(command.getBoardNo()) && o.getP().equals(command.getChannelNo()))) {
                return;
            }

            var current = Math.abs(o.getC());
            var voltage = Math.abs(o.getV());
            var currentNormal = current > NumConstant.INT_FIFTY;
            var voltageNormal = voltage > NumConstant.INT_TWO_THOUSAND;

            currentNum.set(current);
            voltageNum.set(voltage);

            // 1、不是搁置工步 电流大于50mA而且电压大于2V,可视为第一帧数据 2、搁置工步 电压大于2V,可视为第一帧数据
            var isSlTypeFirstData = isSl && voltageNormal;
            var isNotSlTypeFirstData = !isSl && currentNormal && voltageNormal;
            // 不是搁置工艺的电压大于2V而且电流小于50mA的属于小电流,视为无效数据
            var isNotSlTypeButCurrentNotNormal = !isSl && voltageNormal && !currentNormal;

            setCache(currentNormal, voltageNormal, isNotSlTypeButCurrentNotNormal, cab, b.getC(), o.getP());

            if (isNotSlTypeButCurrentNotNormal) {
                return;
            }

            if (isSlTypeFirstData || isNotSlTypeFirstData) {
                var notNormalKey = CaffeineUtil.FIRST_DATA_NOT_NORMAL_CACHE_KEY + CaffeineUtil.getCacheKey(cab, b.getC(), o.getP());
                CaffeineUtil.delete(notNormalKey);
                // 查询需要判断第一帧数据的缓存
                var key = CaffeineUtil.FIRST_DATA_CACHE_PREFIX + CaffeineUtil.getCacheKey(cab, b.getC(), o.getP());
                CommandFirst cache = CaffeineUtil.get(key);
                if (null == cache) {
                    log.info("[single]首个上送数据缓存CommandFirst查询不到key:{}", key);
                    return;
                }

                // 开启定时任务
                cache.setBoardNo(b.getC());
                cache.setChannelNo(o.getP());
                // 定时任务开启成功，删除缓存
                if (jobReStartService.singleChannelJob(cache)) {
                    CaffeineUtil.delete(key);
                }
            }
        })));

        try {
            thread.join();
        } catch (InterruptedException e) {
            log.error("单通道-channelRead:{}", e.getMessage());
        }

        var currentNormal = currentNum.get() > NumConstant.INT_FIFTY;
        var voltageNormal = voltageNum.get() > NumConstant.INT_TWO_THOUSAND;
        // 1、不是搁置工步 电流大于50mA而且电压大于2V,可视为第一帧数据 2、搁置工步 电压大于2V,可视为第一帧数据
        var normal = (isSl && voltageNormal) || (!isSl && currentNormal && voltageNormal);
        if (!normal) {
            log.info("单通道-设置定时失败,currentNum:{},voltageNum:{}-{}", currentNum.get(), voltageNum.get(), gson.toJson(command));
            return;
        }

        //log.info("单通道-指令查询需要判断第一帧数据的缓存:{},{}", singleCommand, cab);
        var cacheKey = CaffeineUtil.getCacheKey(cab, command.getBoardNo(), command.getChannelNo(), command.getOrder());
        // 时间增加3秒，保证指令下发成功后，定时任务能立即执行
        var time = command.getExpectedTimeSecond() * NumConstant.LONG_ONE + NumConstant.LONG_THREE;
        CaffeineUtil.delete(CaffeineUtil.CACHE_KEY_COMMAND + cacheKey);
        CaffeineUtil.set(CaffeineUtil.CACHE_KEY_COMMAND + cacheKey, command, time);
        log.info("单通道-指令设置定时,key:{},time:{}-{}", cacheKey, time, gson.toJson(command));

        CaffeineUtil.delete(CaffeineUtil.FIRST_DATA_SINGLE_CACHE_PREFIX + cab + "_" + command.getBoardNo() + "_" + command.getChannelNo());
    }

    private boolean hasNormal(int cabinetNo) {
        var currentKey = CaffeineUtil.FIRST_DATA_CURRENT_CACHE_KEY + CabinetNoUtil.getCabinetNo(String.valueOf(cabinetNo));

        Map<String, CaffeineUtil.CacheObject<?>> currentMap = CaffeineUtil.getAllStartWith(currentKey);
        if (CollectionUtils.isEmpty(currentMap)) {
            return false;
        }

        List<Integer> currentList = currentMap.values().stream()
                .filter(v -> v instanceof CaffeineUtil.CacheObject<?> cacheObject
                        && cacheObject.data instanceof Integer i)
                .map(v -> (Integer) v.data)
                .toList();

        return !CollectionUtils.isEmpty(currentList) && currentList.getFirst() > NumConstant.INT_ZERO;
    }

    private boolean hasVolNormal(int cabinetNo) {
        var voltageKey = CaffeineUtil.FIRST_DATA_VOLTAGE_CACHE_KEY + CabinetNoUtil.getCabinetNo(String.valueOf(cabinetNo));

        Map<String, CaffeineUtil.CacheObject<?>> currentMap = CaffeineUtil.getAllStartWith(voltageKey);
        if (CollectionUtils.isEmpty(currentMap)) {
            return false;
        }

        List<Integer> currentList = currentMap.values().stream()
                .filter(v -> v instanceof CaffeineUtil.CacheObject<?> cacheObject
                        && cacheObject.data instanceof Integer i)
                .map(v -> (Integer) v.data)
                .toList();

        return !CollectionUtils.isEmpty(currentList) && currentList.getFirst() > NumConstant.INT_ZERO;
    }

    private Pair<Boolean, List<Integer>> allCheck(CommandIssuedSuccess command, Integer cab) {
        if (null == command || null == command.getExpectedTimeSecond() || null == cab) {
            //log.error("整体指令下发首个数据处理异常:{}", gson.toJson(command));
            return Pair.of(false, Collections.emptyList());
        }

        // 终止指令
        if (NumConstant.LONG_LT_ZERO == command.getStepId()) {
            log.info("[终止指令]整体指令下发首个数据处理不处理:{}", gson.toJson(command));
            return Pair.of(false, Collections.emptyList());
        }

        var boardNoList = doorsService.getBoardNoList();
        if (CollectionUtils.isEmpty(boardNoList)) {
            return Pair.of(false, Collections.emptyList());
        }

        // 通道不对的
        if (!String.valueOf(cab).equalsIgnoreCase(command.getReqCabinetNo())) {
            log.info("整体指令下发首个数据处理失败,通道不对的:{}", gson.toJson(command));
            return Pair.of(false, Collections.emptyList());
        }

        return Pair.of(true, boardNoList);
    }

    private Pair<Boolean, List<Integer>> singleCheck(CommandIssuedSuccess command, Integer cab) {
        if (null == command || null == command.getExpectedTimeSecond() || null == cab) {
            log.info("单个通道指令操作不能为空");
            return Pair.of(false, Collections.emptyList());
        }

        // 终止指令
        if (NumConstant.LONG_LT_ZERO == command.getStepId()) {
            return Pair.of(false, Collections.emptyList());
        }

        var boardNoList = doorsService.getBoardNoList();
        if (CollectionUtils.isEmpty(boardNoList)) {
            return Pair.of(false, Collections.emptyList());
        }

        // 通道不对的
        if (!String.valueOf(cab).equalsIgnoreCase(command.getReqCabinetNo())) {
            return Pair.of(false, Collections.emptyList());
        }

        return Pair.of(true, boardNoList);
    }

    private void setCache(boolean currentNormal, boolean voltageNormal, boolean isNotNormal, int cab, int boardNo, int channelNo) {
        // 电流大于50mA
        if (currentNormal) {
            var currentKey = CaffeineUtil.FIRST_DATA_CURRENT_CACHE_KEY + CaffeineUtil.getCacheKey(cab, boardNo, channelNo);
            if (null == CaffeineUtil.get(currentKey)) {
                CaffeineUtil.set(currentKey, NumConstant.INT_ONE, 50);
            }
        }

        // 电压大于2V
        if (voltageNormal) {
            var voltageKey = CaffeineUtil.FIRST_DATA_VOLTAGE_CACHE_KEY + CaffeineUtil.getCacheKey(cab, boardNo, channelNo);
            if (null == CaffeineUtil.get(voltageKey)) {
                CaffeineUtil.set(voltageKey, NumConstant.INT_ONE, 50);
            }
        }

        if (isNotNormal) {
            var notNormalKey = CaffeineUtil.FIRST_DATA_NOT_NORMAL_CACHE_KEY + CaffeineUtil.getCacheKey(cab, boardNo, channelNo);
            FirstDataNotNormalCache cache = CaffeineUtil.get(notNormalKey);
            if (null == cache) {
                cache = new FirstDataNotNormalCache();
                cache.setCount(NumConstant.INT_ZERO);
            }

            if (cache.getCount() < NumConstant.INT_FOUR) {
                cache.setCabinetNo(cab);
                cache.setBoardNo(boardNo);
                cache.setChannelNo(channelNo);
                cache.setCount(cache.getCount() + NumConstant.INT_ONE);
                CaffeineUtil.set(notNormalKey, cache, 20);
            } else {
                var currentKey = CaffeineUtil.FIRST_DATA_CURRENT_CACHE_KEY + CaffeineUtil.getCacheKey(cab, boardNo, channelNo);
                if (null == CaffeineUtil.get(currentKey)) {
                    CaffeineUtil.set(currentKey, NumConstant.INT_ONE, 50);
                }
            }
        }
    }
}
